#region Copyright (c) 2006-2009 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2009 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Reflection;
using System.Collections;

namespace Widgetsphere.Generator.Common.Util
{
	public class ReflectionHelper
	{

		#region Constructor

		private ReflectionHelper()
		{
		}

		#endregion

		#region CreateInstance

		public static Object CreateInstance(string assemblyName, string type)
		{
			try
			{
				System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(assemblyName);

				// Calls through reflection mask exceptions in a 
				// TargetInvocationException, which is annoying.
				// Un-mask by rethrowing the inner exception
        object o = assembly.CreateInstance(type, true);
        return o;
			}
			catch(TargetInvocationException e)
			{
				throw e.InnerException;
			}
			catch (Exception ex)
			{
				throw ex;
			}

		}
		
		public static Object CreateInstance(System.Type type, Object[] args)
		{
			try
			{
				// Calls through reflection mask exceptions in a 
				// TargetInvocationException, which is annoying.
				// Un-mask by rethrowing the inner exception
				return Activator.CreateInstance(type, args); 
			}
			catch(TargetInvocationException e)
			{
				throw e.InnerException;
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		public static Object CreateInstance(Type type)
		{
			return Activator.CreateInstance(type);
		}

		#endregion

    #region GetType

    public static Type GetType(string assemblyName, string type)
    {
      try
      {
        System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(assemblyName);

        // Calls through reflection mask exceptions in a 
        // TargetInvocationException, which is annoying.
        // Un-mask by rethrowing the inner exception
        Type o = assembly.GetType(type, true);
        return o;
      }
      catch(TargetInvocationException e)
      {
        throw e.InnerException;
      }
      catch(Exception ex)
      {
        throw ex;
      }

    }

    #endregion

		#region LoadAllAssembliesForPath

		private static ArrayList LoadAllAssembliesForPath(string path)
		{
			//Store the current assembly file name
			string current = Assembly.GetExecutingAssembly().Location.ToLower();

			ArrayList assemblyList = new ArrayList();
			string[] files = System.IO.Directory.GetFiles(path, "*.dll");
			foreach(string fileName in files)
			{
				if (!fileName.ToLower().Equals(current))
				{
					//try loading this file as an assembly
					try
					{
						System.Reflection.Assembly assembly = Assembly.LoadFrom(fileName);
						assemblyList.Add(assembly);
					}
					catch (Exception ex)
					{
						//Do nothing as the file is not a valid VS.NET file
						System.Diagnostics.Trace.WriteLine(ex.ToString());
					}
				}
			}

			string executingAssemblyPath = Assembly.GetExecutingAssembly().Location;
			System.IO.FileInfo fi = new System.IO.FileInfo(executingAssemblyPath);
			executingAssemblyPath = fi.DirectoryName;
			if (StringHelper.Match(path, executingAssemblyPath, true))
			{
				assemblyList.Add(Assembly.GetExecutingAssembly());
			}
			return assemblyList;
		}

		#endregion

		#region GetObjectsFromPath
		public static System.Type[] GetCreatableObjects(System.Type parentType, string path)
		{
			ArrayList retval = new ArrayList();
			ArrayList al = LoadAllAssembliesForPath(path);

			try
			{
				foreach (System.Reflection.Assembly assembly in al)
				{
					System.Diagnostics.Debug.WriteLine(assembly.Location);
					foreach (Type t in assembly.GetTypes())
					{
						if (parentType.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)
							retval.Add(t);
						else if (t.IsAssignableFrom(parentType) && !t.IsAbstract && !t.IsInterface)
							retval.Add(t);
					}
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			
			return (System.Type[])retval.ToArray(typeof(System.Type));
		}

		#endregion

    #region GetByAttribute
    public static Hashtable GetFieldsByAttribute(object o, System.Type attributeType)
    {
      try
      {
        Type objectType = o.GetType();
        Hashtable retval = new Hashtable();
        FieldInfo[] fields = objectType.GetFields();
        foreach (FieldInfo field in fields)
        {
          object[] attributes = field.GetCustomAttributes(attributeType, true);
          if (attributes.Length > 0)
          {
            retval.Add(field, attributes[0]);
          }
        }
        return retval;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

		public static Hashtable GetMethodsByAttribute(System.Type parentType, System.Type attributeType)
		{
			try
			{
				Hashtable retval = new Hashtable();
				MethodInfo[] methods = parentType.GetMethods();
				foreach (MethodInfo m in methods)
				{
					object[] attributes = m.GetCustomAttributes(attributeType, true);
					if (attributes.Length > 0)
					{
						retval.Add(attributes[0], m);
					}
				}

				//Sort the array

				return retval;
			}
			catch (Exception ex)
			{
				throw ex;
			}			
		}

		#endregion

		#region GetSingleAttribute

		public static Attribute GetSingleAttribute(System.Type attributeType, object instance)
		{
			try
			{
				Hashtable retval = new Hashtable();
				Attribute[] attributes = (Attribute[])instance.GetType().GetCustomAttributes(attributeType, true);
				if (attributes.Length > 0)
					return attributes[0];
				else
					return null;
			}
			catch (Exception ex)
			{
				throw ex;
			}			
		}

		public static Attribute GetSingleAttribute(System.Type attributeType, System.Type type)
		{
			try
			{
				Hashtable retval = new Hashtable();
				Attribute[] attributes = (Attribute[])type.GetCustomAttributes(attributeType, true);
				if (attributes.Length > 0)
					return attributes[0];
				else
					return null;
			}
			catch (Exception ex)
			{
				throw ex;
			}			
		}

		public static Attribute[] GetAttributes(System.Type attributeType, object instance)
		{
			try
			{
				Hashtable retval = new Hashtable();
				Attribute[] attributes = (Attribute[])instance.GetType().GetCustomAttributes(attributeType, true);
				return attributes;
			}
			catch (Exception ex)
			{
				throw ex;
			}			
		}

		#endregion

    #region IsTypeOf

    public static bool IsTypeOf(System.Type checkType, string baseType)
    {
      if(checkType == null)
        return false;
      while((checkType != null) && (checkType.ToString() != baseType))
      {
        checkType = checkType.BaseType;
      }
      return (checkType != null);
    }

    public static bool IsTypeOf(System.Type checkType, System.Type baseType)
    {
      return IsTypeOf(checkType, baseType.ToString());
    }

    #endregion

		public static void DisplayProperties(object o)
		{
			foreach(PropertyInfo info in o.GetType().GetProperties())
			{
				System.Diagnostics.Debug.WriteLine(info.Name);
			}
		}

		public static void DisplayObjectTypes(object o)
		{
			foreach(System.Type t1 in o.GetType().GetNestedTypes())
			{
				System.Diagnostics.Debug.WriteLine(t1.ToString());
			}
			foreach(System.Type t in o.GetType().GetInterfaces())
			{
				System.Diagnostics.Debug.WriteLine(t.ToString());
			}
			foreach(MethodInfo mi in o.GetType().GetMethods())
			{
				System.Diagnostics.Debug.WriteLine(mi.Name);
			}
		}

		#region Implements Interface
		public static bool ImplementsInterface(object o, Type interfaceType)
		{
			foreach(System.Type t in o.GetType().GetInterfaces())
			{
				if (t == interfaceType)
					return true;
			}
			return false;
		}
		public static bool ImplementsInterface(Type objectType, Type interfaceType)
		{
			foreach(System.Type t in objectType.GetInterfaces())
			{
				if (t == interfaceType)
					return true;
			}
			return false;
		}
    
    public static System.Type[] GetCreatableObjectImplementsInterface(Type interfaceType, Assembly assembly)
    {
      ArrayList retval = new ArrayList();
      try
      {
        foreach(Type t in assembly.GetTypes())
        {
          if(ImplementsInterface(t, interfaceType) && !t.IsAbstract && !t.IsInterface)
            retval.Add(t);
        }
      }
      catch(Exception ex)
      {
        System.Diagnostics.Trace.WriteLine("Could not load types for assembly: " + assembly.FullName);
      }
      return (System.Type[])retval.ToArray(typeof(System.Type));
    }
		
    public static System.Type[] GetCreatableObjectImplementsInterface(Type interfaceType, string path)
		{
      ArrayList al = new ArrayList();
      if(System.IO.File.Exists(path))
        al.Add(Assembly.LoadFile(path));
      else
        al = LoadAllAssembliesForPath(StringHelper.EnsureDirectorySeperatorAtEnd(path));

			ArrayList retval = new ArrayList();			
			try
			{
				foreach (System.Reflection.Assembly assembly in al)
				{
					try
					{            
						foreach (Type t in assembly.GetTypes())
						{
							if (ImplementsInterface(t, interfaceType) && !t.IsAbstract && !t.IsInterface)
								retval.Add(t);
						}
					}
          catch(System.Reflection.ReflectionTypeLoadException ex)
          {
            System.Diagnostics.Trace.WriteLine("Could not load types for assembly: " + assembly.FullName);
            foreach (Exception innerEx in ex.LoaderExceptions)
            {
              System.Diagnostics.Trace.WriteLine("Loader Exception: " + innerEx.Message);
            }
          }
					catch(Exception ex)
					{
						System.Diagnostics.Trace.WriteLine("Could not load types for assembly: " + assembly.FullName);
					}				
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
			
			return (System.Type[])retval.ToArray(typeof(System.Type));
		}
		#endregion

	}
}
